package org.yysd;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.yysd.pojo.CustomPagePanelConfig;
import org.yysd.pojo.NameValuePair;
import org.yysd.pojo.RequestArgs;
import org.yysd.pojo.ResponseResult;
import org.yysd.util.HttpClientUtil;
import org.yysd.util.IHttpRequest;
import org.yysd.util.WidgetUtil;
import org.yysd.widget.CustomPagePanel;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class Mainwindow {
    private static final String CONF_DIR_NAME = "RequestWorksData";
    private static final String PAGE_LIST_FILE_NAME = "page-list.json";

    private int rowHeight = 30; // 自定义行高
    private JFrame jFrame;
    private JTabbedPane tabbedPane;
    private Map<String, CustomPagePanel> pagePanelMap;
    private Integer tabCount = 1;
    private File confDir;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    // 用程序的 PlasticLookAndFeel 主题设置为 Experience Blue 主题。这会影响到整个应用程序中使用 PlasticLookAndFeel 的组件的外观。
                    //PlasticLookAndFeel.setPlasticTheme(new ExperienceBlue());
                    // 设置 JGoodies Windows 样式
                    UIManager.setLookAndFeel(new WindowsLookAndFeel());
                    //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                    //
                    Mainwindow window = new Mainwindow();
                    window.jFrame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public Mainwindow() {
        try {
            initialize();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() throws Exception {
        jFrame = new JFrame();
        jFrame.setTitle("RequestWorks");
        jFrame.setBounds(100, 100, 840, 521);
        jFrame.setLocationRelativeTo(null);// 显示屏幕中间,写在设置窗体大小的后面
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 获取图片资源的路径
        URL imagePath = Mainwindow.class.getClassLoader().getResource("sym_def_app_icon.png");
        //URL imagePath = ResourceUtil.getResource("sym_def_app_icon.png");
        // 加载图标文件
        ImageIcon icon = new ImageIcon(imagePath);
        // 设置窗口图标
        jFrame.setIconImage(icon.getImage());

//        JMenuBar menuBar = new JMenuBar();
//        jFrame.setJMenuBar(menuBar);

        pagePanelMap = new LinkedHashMap<>();

//        JMenu fileMenu = new JMenu("文件");
//        menuBar.add(fileMenu);

//        JMenuItem mntmNewMenuItem = new JMenuItem("新建...");
//        mntmNewMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
//        fileMenu.add(mntmNewMenuItem);
//        mntmNewMenuItem.addActionListener(new ActionListener() {
//            public void actionPerformed(ActionEvent e) {
//                addTabPage(null);
//            }
//        });

        tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        tabbedPane.setFont(new Font("宋体", Font.PLAIN, 18));
        jFrame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
        //
        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        jFrame.getContentPane().add(toolBar, BorderLayout.NORTH);
        //
        JButton btnNewtab = new JButton("新建...");
        btnNewtab.setFont(new Font("宋体", Font.PLAIN, 18));
        btnNewtab.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("新建");
                addTabPage(null);
            }
        });
        toolBar.add(btnNewtab);

        JButton btnNewButton = new JButton("重命名");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int selectedIndex = tabbedPane.getSelectedIndex();
                if (selectedIndex == -1) return;
                Component componentAt = tabbedPane.getComponentAt(selectedIndex);
                CustomPagePanel customPagePanel = (CustomPagePanel) componentAt;

                System.out.println("重命名");

                // 显示输入对话框，并获取用户输入的文本
                String userInput = JOptionPane.showInputDialog(jFrame, "请输入新名称:", customPagePanel.tabName);

                // 检查用户是否点击了"取消"或者直接关闭了对话框
                if (userInput == null || userInput.trim().isEmpty()) {
                    System.out.println("用户取消了操作或未输入内容。");
                } else {
                    // 用户输入了文本
                    System.out.println("用户输入的内容是: " + userInput);


                    customPagePanel.tabName = userInput;
                    tabbedPane.setTitleAt(selectedIndex, userInput);
                    try {
                        File file = FileUtils.getFile(confDir, customPagePanel.tabId + ".json");
                        String s = null;
                        if (file.exists()) {
                            s = FileUtils.readFileToString(file, "UTF-8");
                        } else {
                            file.createNewFile();
                            CustomPagePanelConfig config = WidgetUtil.getCustomPagePanelConfig(customPagePanel);
                            s = JSON.toJSONString(config);
                        }

                        JSONObject jsonObject = JSON.parseObject(s);
                        jsonObject.put("tabName", userInput);
                        jsonObject.put("tabId", customPagePanel.tabId);

                        String jsonString = formatObjectJson(jsonObject);
                        FileUtils.writeStringToFile(file, jsonString, "UTF-8");
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                }
            }
        });
        btnNewButton.setFont(new Font("宋体", Font.PLAIN, 18));
        toolBar.add(btnNewButton);
        //
        JPopupMenu popupMenu = new JPopupMenu();
        tabbedPane.setComponentPopupMenu(popupMenu);

        JMenuItem closeMenuItem_1 = new JMenuItem("关闭");
        popupMenu.add(closeMenuItem_1);
        closeMenuItem_1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectedIndex = tabbedPane.getSelectedIndex();
                if (selectedIndex >= 0) {
                    Component componentAt = tabbedPane.getComponentAt(selectedIndex);
                    if (componentAt instanceof CustomPagePanel) {
                        CustomPagePanel customPagePanel = (CustomPagePanel) componentAt;
                        String tabId = customPagePanel.tabId;
                        pagePanelMap.remove(tabId);
                        File file = FileUtils.getFile(confDir, tabId + ".json");
                        file.delete();
                    }
                    tabbedPane.removeTabAt(selectedIndex);
                    writePagePanelListConfig();
                }
            }
        });
        //
        ProtectionDomain protectionDomain = Mainwindow.class.getProtectionDomain();
        CodeSource codeSource = protectionDomain.getCodeSource();
        File jarFile = new File(codeSource.getLocation().toURI());
        String workDir = jarFile.getParentFile().getAbsolutePath();
        System.out.println("当前JAR包的路径是: " + workDir);
        //
        confDir = FileUtils.getFile(workDir, CONF_DIR_NAME);
        if (!confDir.exists()) {
            if (!confDir.mkdirs()) throw new Exception("配置目录创建异常:" + confDir);
        }

        File confListFile = FileUtils.getFile(confDir, PAGE_LIST_FILE_NAME);
        if (confListFile.exists()) {
            String string = FileUtils.readFileToString(confListFile, "UTF-8");
            List<String> stringList = JSON.parseArray(string, String.class);
            for (String s : stringList) {
                this.addTabPage(s);
                CustomPagePanel customPagePanel = pagePanelMap.get(s);
                File file = FileUtils.getFile(confDir, s + ".json");
                if (!file.exists()) continue;
                String text = FileUtils.readFileToString(file, "UTF-8");
                CustomPagePanelConfig config = JSON.parseObject(text, CustomPagePanelConfig.class);
                customPagePanel = WidgetUtil.initCustomPagePanel(customPagePanel, config);
                tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), config.tabName);
                WidgetUtil.setMap(customPagePanel.model, config.heaherMap);
                WidgetUtil.setMap(customPagePanel.model_1, config.parameMap);
            }
        }
        if (pagePanelMap.values().size() == 0) {
            addTabPage(null);
        }
    }

    //新增新的标签页
    public void addTabPage(String tabId) {
        CustomPagePanel curPanel = new CustomPagePanel();
        //String format = String.format("<html><body width='100px'>Tab %s</body></html>", size);
        curPanel.tabName = String.format("  New tab%s  ", tabCount++);
        if (StringUtils.isBlank(tabId)) {
            tabId = StringUtils.replace(UUID.randomUUID().toString(), "-", "").toUpperCase();
        }
        curPanel.tabId = tabId;
        //
        //pagePanelList.add(curPanel);
        pagePanelMap.put(curPanel.tabId, curPanel);
        //
        writePagePanelListConfig();
        //
        tabbedPane.addTab(curPanel.tabName, null, curPanel, null);
        curPanel.setLayout(new BorderLayout(0, 0));
        tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
        //
        Box verticalBox = Box.createVerticalBox();
        curPanel.add(verticalBox, BorderLayout.NORTH);
        curPanel.textArea = new JTextArea();
        curPanel.textArea.setBackground(Color.LIGHT_GRAY);
        curPanel.textArea.setEditable(false);
        curPanel.textArea.setLineWrap(true);
        verticalBox.add(curPanel.textArea);

        Box horizontalBox = Box.createHorizontalBox();
        verticalBox.add(horizontalBox);

        curPanel.comboBox = new JComboBox();
        curPanel.comboBox.setFont(new Font("宋体", Font.PLAIN, 18));
        curPanel.comboBox.setModel(new DefaultComboBoxModel(new String[]{"GET", "POST", "PUT", "DELETE"}));
        horizontalBox.add(curPanel.comboBox);

        curPanel.textArea_url = new JTextField();
        horizontalBox.add(curPanel.textArea_url);
        curPanel.textArea_url.setColumns(10);

        JButton btnSendButton = new JButton("发 送");
        btnSendButton.setFont(new Font("宋体", Font.PLAIN, 18));
        horizontalBox.add(btnSendButton);

        btnSendButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                curPanel.rSyntaxTextArea.setText("");
                String httpMethod = curPanel.comboBox.getSelectedItem().toString();
                String url = curPanel.textArea_url.getText().trim();
                if (StringUtils.isBlank(url)) return;
                if (!url.startsWith("http://") && !url.startsWith("https://")) {
                    url = "http://" + url;
                }
                // 获取JTable的数据到Map
                Map<String, String> headerMap = WidgetUtil.getMap(curPanel.model);
                Map<String, String> parameMap = WidgetUtil.getMap(curPanel.model_1);

                RequestArgs requestArgs = new RequestArgs();
                requestArgs.setHttpMethod(httpMethod);
                requestArgs.setUrl(url);
                requestArgs.setHeaderMap(headerMap);
                requestArgs.setParameMap(parameMap);
                requestArgs.setJsonBody(curPanel.rTextArea.getText());
                StopWatch stopWatch = new StopWatch();
                try {
                    IHttpRequest httpRequest = new HttpClientUtil();
                    stopWatch.start();
                    ResponseResult responseResult = httpRequest.send(requestArgs);
                    stopWatch.stop();
                    String responseBody = responseResult.getBody();
                    boolean isJson = isJson(responseBody);
                    if (isJson) responseBody = formatJson(responseBody);
                    curPanel.textArea.setText(responseResult.getRequestUrl());
                    curPanel.rSyntaxTextArea.setText(responseBody);
                    // 判断返回结果类型
                    if (isJson) {
                        // 设置JSON语法高亮
                        curPanel.rSyntaxTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
                    } else {
                        // 设置HTML语法高亮
                        curPanel.rSyntaxTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_HTML);
                    }
                    String format = String.format("Status: %s    Time: %s ms", responseResult.getStatus(), stopWatch.getTime(TimeUnit.MILLISECONDS));
                    curPanel.statusLabel.setText(format);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    curPanel.textArea.setText("");
                    curPanel.rSyntaxTextArea.setText(ExceptionUtils.getStackTrace(ex));
                    curPanel.statusLabel.setText("发送异常");
                }
                // 设置光标位置到第一行
                curPanel.rSyntaxTextArea.setCaretPosition(0);
                try {
                    CustomPagePanelConfig config = WidgetUtil.getCustomPagePanelConfig(curPanel);
                    File file = FileUtils.getFile(confDir, curPanel.tabId + ".json");
                    String jsonString = formatObjectJson(config);
                    FileUtils.writeStringToFile(file, jsonString, "UTF-8");
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });

        JSplitPane splitPane = new JSplitPane();
        splitPane.setContinuousLayout(true);
        splitPane.setDividerSize(10);
        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        curPanel.add(splitPane, BorderLayout.CENTER);

        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        splitPane.setLeftComponent(tabbedPane);
        tabbedPane.setFont(new Font("宋体", Font.PLAIN, 18));

        JPanel panel = new JPanel();
        tabbedPane.addTab("请求头", null, panel, null);
        panel.setLayout(new BorderLayout(0, 0));

        {
            JScrollPane scrollPane = new JScrollPane();
            panel.add(scrollPane, BorderLayout.CENTER);

            // 创建表格模型
            curPanel.model = new DefaultTableModel();
            curPanel.model.addColumn("Key");
            curPanel.model.addColumn("Value");
            //添加默认请求头
            curPanel.model.addRow(new String[]{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"});

            curPanel.table = new JTable(curPanel.model);
            // 设置行高
            curPanel.table.setRowHeight(rowHeight);
            scrollPane.setViewportView(curPanel.table);

            Box horizontalBox_1 = Box.createHorizontalBox();
            panel.add(horizontalBox_1, BorderLayout.NORTH);

            JButton addButton = new JButton("添加");
            addButton.setFont(new Font("宋体", Font.PLAIN, 18));
            horizontalBox_1.add(addButton);

            JButton deleteButton = new JButton("删除");
            deleteButton.setFont(new Font("宋体", Font.PLAIN, 18));
            horizontalBox_1.add(deleteButton);

            // 创建添加按钮
            addButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    curPanel.model.addRow(new Object[]{"", ""});
                }
            });

            // 创建删除按钮
            deleteButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int selectedRow = curPanel.table.getSelectedRow();
                    if (selectedRow != -1) {
                        curPanel.model.removeRow(selectedRow);
                    }
                }
            });
        }

        JPanel panel_1 = new JPanel();
        tabbedPane.addTab("查询参数", null, panel_1, null);
        panel_1.setLayout(new BorderLayout(0, 0));

        {
            Box horizontalBox_1 = Box.createHorizontalBox();
            panel_1.add(horizontalBox_1, BorderLayout.NORTH);

            JButton addButton = new JButton("添加");
            addButton.setFont(new Font("宋体", Font.PLAIN, 18));
            horizontalBox_1.add(addButton);

            JButton deleteButton = new JButton("删除");
            deleteButton.setFont(new Font("宋体", Font.PLAIN, 18));
            horizontalBox_1.add(deleteButton);

            JButton parseTrimURLButton = new JButton("解析修剪URL");
            parseTrimURLButton.setFont(new Font("宋体", Font.PLAIN, 18));
            horizontalBox_1.add(parseTrimURLButton);

            parseTrimURLButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
//                    while (curPanel.model_1.getRowCount() > 0) {
//                        curPanel.model_1.removeRow(0);
//                    }
                    String urlString = curPanel.textArea_url.getText();
                    String query = "";
                    String[] split = StringUtils.split(urlString, "?");
                    if (split.length == 2) {
                        query = split[1];
                        curPanel.textArea_url.setText(split[0]);
                    }
                    List<NameValuePair> nameValuePairs = parseQueryParams(query);
                    for (NameValuePair pair : nameValuePairs) {
                        curPanel.model_1.addRow(new String[]{pair.getName(), pair.getValue()});
                    }
                }
            });

            JScrollPane scrollPane = new JScrollPane();
            panel_1.add(scrollPane, BorderLayout.CENTER);

            // 创建表格模型
            curPanel.model_1 = new DefaultTableModel();
            curPanel.model_1.addColumn("Key");
            curPanel.model_1.addColumn("Value");

            curPanel.table_1 = new JTable(curPanel.model_1);
            // 设置行高
            curPanel.table_1.setRowHeight(rowHeight);
            scrollPane.setViewportView(curPanel.table_1);

            // 创建添加按钮
            addButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    curPanel.model_1.addRow(new Object[]{"", ""});
                }
            });

            // 创建删除按钮
            deleteButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int selectedRow = curPanel.table_1.getSelectedRow();
                    if (selectedRow != -1) {
                        curPanel.model_1.removeRow(selectedRow);
                    }
                }
            });
        }

        JPanel panel_2 = new JPanel();
        tabbedPane.addTab("请求体", null, panel_2, null);
        panel_2.setLayout(new BorderLayout(0, 0));

        RTextScrollPane scrollPane = getRTextScrollPane();
        curPanel.rTextArea = scrollPane.getTextArea();
        panel_2.add(scrollPane, BorderLayout.CENTER);

        //JScrollPane scrollPane = new JScrollPane();
        //splitPane.setRightComponent(scrollPane);
        //JTextArea textArea = new JTextArea();
        //scrollPane.setViewportView(textArea);

        curPanel.rSyntaxTextArea = new RSyntaxTextArea(1, 1);
        curPanel.rSyntaxTextArea.setAutoIndentEnabled(false);//取消自动缩进
        curPanel.rSyntaxTextArea.setEditable(false);
        curPanel.rSyntaxTextArea.setTabSize(4);
        curPanel.rSyntaxTextArea.setFont(new Font("宋体", Font.BOLD, 22));
        curPanel.rSyntaxTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE);
        curPanel.rSyntaxTextArea.setCodeFoldingEnabled(true);
        RTextScrollPane sp = new RTextScrollPane(curPanel.rSyntaxTextArea);
        splitPane.setRightComponent(sp);

        curPanel.statusLabel = new JLabel(" ");
        sp.setColumnHeaderView(curPanel.statusLabel);
        splitPane.setDividerLocation(300);
    }

    public void writePagePanelListConfig() {
        File confListFile = FileUtils.getFile(confDir, PAGE_LIST_FILE_NAME);
        LinkedList<String> idLinkedList = pagePanelMap.values().stream()
                .map(panel -> panel.tabId)
                .collect(Collectors.toCollection(LinkedList::new));
        try {
            FileUtils.writeStringToFile(confListFile, formatObjectJson(idLinkedList), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public RTextScrollPane getRTextScrollPane() {
        RSyntaxTextArea rSyntaxTextArea = new RSyntaxTextArea(1, 1);
        rSyntaxTextArea.setAutoIndentEnabled(false);//取消自动缩进
        rSyntaxTextArea.setTabSize(4);
        rSyntaxTextArea.setFont(new Font("宋体", Font.BOLD, 22));
        rSyntaxTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE);
        rSyntaxTextArea.setCodeFoldingEnabled(true);
        RTextScrollPane sp = new RTextScrollPane(rSyntaxTextArea);
        return sp;
    }

    // 判断字符串是否为合法的JSON格式
    private static boolean isJson(String text) {
        if (StringUtils.isBlank(text)) return false;
        try {
            if (text.trim().startsWith("[")) {
                JSON.parseArray(text);
            } else {
                JSON.parseObject(text);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 格式化JSON字符串
     *
     * @param data JSON字符串
     * @return 格式化后JSON字符串
     */
    public static String formatJson(String data) {
        if (StringUtils.isBlank(data)) return null;
        Object object;
        if (data.trim().startsWith("[")) {
            object = JSON.parseArray(data);
        } else {
            object = JSON.parseObject(data);
        }
        String string = JSON.toJSONString(object, true);
        //String pretty = JSONObject.toJSONString(object, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);
        //String string = JSON.toJSONString(object, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteNullListAsEmpty);
        return string;
    }

    public static String formatObjectJson(Object object) {
        //String pretty = JSONObject.toJSONString(object, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);
        String string = JSON.toJSONString(object, true);
        //String string = JSON.toJSONString(object, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.WriteMapNullValue, JSONWriter.Feature.WriteNullListAsEmpty);
        return string;
    }

    private static List<NameValuePair> parseQueryParams(String query) {
        Map<String, String> queryParams = new LinkedHashMap<>();
        List<NameValuePair> list = new LinkedList<>();
        if (StringUtils.isNotBlank(query)) {
            String[] params = StringUtils.split(query, "&");
            for (String param : params) {
                String[] keyValue = StringUtils.split(param, "=");
                NameValuePair nameValuePair = new NameValuePair();
                if (keyValue.length == 2) {
                    queryParams.put(keyValue[0], keyValue[1]);
                    nameValuePair.setName(keyValue[0]);
                    nameValuePair.setValue(keyValue[1]);
                } else if (keyValue.length == 1) {
                    queryParams.put(keyValue[0], "");
                    nameValuePair.setName(keyValue[0]);
                    nameValuePair.setValue("");
                }
                list.add(nameValuePair);
            }
        }
        return list;
    }
}
